package com.asset.dispoal.business.approval.service.command;

import com.asset.dispoal.business.approval.domain.db.entity.BorrowDetail;
import com.asset.dispoal.business.approval.domain.db.mapper.BorrowDetailMapper;
import com.asset.dispoal.business.approval.dto.AuditRequest;
import com.asset.dispoal.business.bsCase.domain.db.entity.BsCase;
import com.asset.dispoal.business.bsCase.domain.db.entity.BsCaseMediation;
import com.asset.dispoal.business.bsCase.domain.db.mapper.BsCaseMapper;
import com.asset.dispoal.business.bsCase.domain.db.mapper.BsCaseMediationMapper;
import com.asset.dispoal.business.mediation.domain.db.entity.ReduceOperate;
import com.asset.dispoal.business.mediation.domain.db.entity.ReduceStagingTmp;
import com.asset.dispoal.business.mediation.domain.db.mapper.ReduceOperateMapper;
import com.asset.dispoal.business.mediation.domain.db.mapper.ReduceStagingTmpMapper;
import com.asset.dispoal.business.repayment.domain.db.entity.BsCaseRepayment;
import com.asset.dispoal.business.repayment.domain.db.entity.BsCaseRepaymentLogs;
import com.asset.dispoal.business.repayment.domain.db.mapper.CaseRepaymentLogsMapper;
import com.asset.dispoal.business.repayment.domain.db.mapper.CaseRepaymentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tech.mhuang.pacebox.core.ddd.BaseCommand;
import tech.mhuang.pacebox.core.exception.BusinessException;
import tech.mhuang.pacebox.springboot.core.local.GlobalHeaderThreadLocal;
import tech.mhuang.pacebox.springboot.protocol.Result;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @description:
 * @author: yf
 * @date: 2022-10-09 10:54:13
 */
@Repository
public class AuditCommand implements BaseCommand<AuditRequest, Result> {
    @Autowired
    private CaseRepaymentLogsMapper caseRepaymentLogsMapper;
    @Autowired
    private BsCaseMapper bsCaseMapper;
    @Autowired
    private BorrowDetailMapper borrowDetailMapper;
    @Autowired
    private CaseRepaymentMapper caseRepaymentMapper;
    @Autowired
    private ReduceStagingTmpMapper reduceStagingTmpMapper;
    @Autowired
    private BsCaseMediationMapper bsCaseMediationMapper;
    @Autowired
    private ReduceOperateMapper reduceOperateMapper;

    @Override
    @Transactional
    public Result execute(AuditRequest request) {
        BsCaseRepaymentLogs repaymentLogs = caseRepaymentLogsMapper.queryById(request.getId());
        String userId = GlobalHeaderThreadLocal.getOrException().getUserId();
        repaymentLogs.setApprovalTime(new Date());
        repaymentLogs.setApproverId(userId);
        repaymentLogs.setApproverName(caseRepaymentLogsMapper.getNickNameByUserId(userId));
        if ("1".equals(request.getOperateType())) {
            repaymentLogs.setApprovalState("2");
            int logsUpdateRes = caseRepaymentLogsMapper.update(repaymentLogs);
            if (logsUpdateRes <= 0) {
                throw new BusinessException(500, "审核操作失败！", "");
            }

            BsCase bsCase = bsCaseMapper.queryById(repaymentLogs.getCaseId());
            //诉讼本金 利息
            BigDecimal lawsuitPrincipal = bsCase.getLawsuitPrincipalAmount().subtract(repaymentLogs.getCurrentRepaymentPrincipal());
            BigDecimal lawsuitInterest = bsCase.getLawsuitInterestAmount().subtract(repaymentLogs.getCurrentRepaymentInterest());
            bsCase.setLawsuitPrincipalAmount(lawsuitPrincipal);
            bsCase.setLawsuitInterestAmount(lawsuitInterest);
            //判决本金，利息，罚息不为空的话也依次扣减
            if (bsCase.getPrincipal() != null) {
                BigDecimal principal = bsCase.getPrincipal().subtract(repaymentLogs.getCurrentRepaymentPrincipal());
                bsCase.setPrincipal(principal);
            }
            if (bsCase.getInterest() != null) {
                BigDecimal interest = bsCase.getInterest().subtract(repaymentLogs.getCurrentRepaymentInterest());
                bsCase.setInterest(interest);
            }
            if (bsCase.getPenaltyInterest() != null) {
                BigDecimal penaltyInterest = bsCase.getPenaltyInterest().subtract(repaymentLogs.getCurrentRepaymentPenalty());
                bsCase.setPenaltyInterest(penaltyInterest);
            }
            int caseUpadateNums = bsCaseMapper.update(bsCase);
            if (caseUpadateNums <= 0) {
                throw new BusinessException(500, "审核异常！！", "");
            }
            //合同集合
            agreementSub(repaymentLogs, bsCase);

            //计算案件是否还清
            // 逻辑(已还金额是否 >= 还金额相等)
            // 和解与调解应该判断当前所还金额是否为最后一期
            switch (bsCase.getCaseState()) {
                case "reconciliation":
                    ReduceStagingTmp reduceStagingTmp = reduceStagingTmpMapper.queryById(repaymentLogs.getRepaymentId());
                    if (caculateReconciliationIsPay(reduceStagingTmp)) {
                        reduceStagingTmp.setIsPay("1");
                        reduceStagingTmpMapper.update(reduceStagingTmp);
                        //判断是否还存在未还的期数
                        List<ReduceOperate> operates = reduceOperateMapper.getLogsByCaseId(repaymentLogs.getCaseId());
                        if (!CollectionUtils.isEmpty(operates)) {
                            int res = reduceStagingTmpMapper.toRepaymentPriod(operates.get(0).getStagingIds());
                            if (res <= 0) {
                                //案件所有期数已还清， 更新主表状态
                                int i = bsCaseMapper.updateRepaymentState(bsCase.getId());
                                if (i <= 0) {
                                    throw new BusinessException(500, "审核操作失败！", "");
                                }
                            }
                        }

                    }
                    break;
                case "mediation":
                    BsCaseMediation caseMediation = bsCaseMediationMapper.queryById(repaymentLogs.getRepaymentId());
                    if (caculateMeditionIsPay(caseMediation)) {
                        caseMediation.setIsPay("1");
                        bsCaseMediationMapper.update(caseMediation);
                        //判断是否还存在未还的期数
                        int res = bsCaseMediationMapper.toRepaymentPriod(repaymentLogs.getCaseId());
                        if (res <= 0) {
                            //案件所有期数已还清， 更新主表状态
                            int i = bsCaseMapper.updateRepaymentState(bsCase.getId());
                            if (i <= 0) {
                                throw new BusinessException(500, "审核操作失败！", "");
                            }
                        }
                    }
                    break;
                default:
                    BsCaseRepayment bsCaseRepayment = caseRepaymentMapper.queryById(repaymentLogs.getRepaymentId());
                    if (caculateDefaultIsPay(bsCaseRepayment)) {
                        bsCaseRepayment.setIsPay("1");
                        caseRepaymentMapper.update(bsCaseRepayment);
                        int i = bsCaseMapper.updateRepaymentState(bsCase.getId());
                        if (i <= 0) {
                            throw new BusinessException(500, "审核操作失败！", "");
                        }
                    }
                    break;
            }
        } else {
            repaymentLogs.setApprovalState("3");
            int logsUpdateRes = caseRepaymentLogsMapper.update(repaymentLogs);
            if (logsUpdateRes <= 0) {
                throw new BusinessException(500, "审核操作失败！", "");
            }
            //还款表已还金额数据回滚
            BsCase bsCase = bsCaseMapper.getCaseById(repaymentLogs.getCaseId());
            switch (bsCase.getCaseState()) {
                case "reconciliation":
                    reconciliationHandler(repaymentLogs);
                    break;
                case "mediation":
                    mediationHandler(repaymentLogs);
                    break;
                default:
                    defaultHandler(repaymentLogs);
                    break;
            }
        }
        return Result.ok();
    }

    /**
     * 合同抵扣处理逻辑
     *
     * @param repaymentLogs
     * @param bsCase
     */
    private void agreementSub(BsCaseRepaymentLogs repaymentLogs, BsCase bsCase) {
        List<BorrowDetail> agreementDetailList = borrowDetailMapper.getAgreementDetailListByCaseId(bsCase.getId());
        BigDecimal totalAmt = repaymentLogs.getCurrentRepaymentPrincipal().add(repaymentLogs.getCurrentRepaymentInterest()).add(repaymentLogs.getCurrentRepaymentPenalty());
        for (BorrowDetail detail : agreementDetailList) {
            if (totalAmt.compareTo(BigDecimal.ZERO) == 0) {
                continue;
            }

            //诉讼本金
            if (BigDecimal.valueOf(detail.getLawsuitPrincipalAmount()).compareTo(totalAmt) == -1) {
                totalAmt = totalAmt.subtract(BigDecimal.valueOf(detail.getLawsuitPrincipalAmount()));
                detail.setLawsuitPrincipalAmount(BigDecimal.ZERO.doubleValue());
            } else {
                BigDecimal principal = BigDecimal.valueOf(detail.getLawsuitPrincipalAmount()).subtract(totalAmt);
                totalAmt = BigDecimal.ZERO;
                detail.setLawsuitPrincipalAmount(principal.doubleValue());
            }
            //诉讼利息
            if (BigDecimal.valueOf(detail.getLawsuitInterestAmount()).compareTo(totalAmt) == -1) {
                totalAmt = totalAmt.subtract(BigDecimal.valueOf(detail.getLawsuitInterestAmount()));
                detail.setLawsuitPrincipalAmount(BigDecimal.ZERO.doubleValue());
            } else {
                BigDecimal principal = BigDecimal.valueOf(detail.getLawsuitInterestAmount()).subtract(totalAmt);
                totalAmt = BigDecimal.ZERO;
                detail.setLawsuitInterestAmount(principal.doubleValue());
            }

            //诉讼罚息
            if (BigDecimal.valueOf(detail.getLitigationFines()).compareTo(totalAmt) == -1) {
                totalAmt = totalAmt.subtract(BigDecimal.valueOf(detail.getLitigationFines()));
                detail.setLitigationFines(BigDecimal.ZERO.doubleValue());
            } else {
                BigDecimal principal = BigDecimal.valueOf(detail.getLitigationFines()).subtract(totalAmt);
                totalAmt = BigDecimal.ZERO;
                detail.setLitigationFines(principal.doubleValue());
            }
        }
        agreementDetailList.parallelStream().forEach(detail -> borrowDetailMapper.update(detail));
    }

    /**
     * 其他 已还金额回滚
     *
     * @param repaymentLogs
     */
    private void defaultHandler(BsCaseRepaymentLogs repaymentLogs) {
        BsCaseRepayment caseRepayment = caseRepaymentMapper.queryById(repaymentLogs.getRepaymentId());
        BigDecimal principalAmt = caseRepayment.getRepaymentPrincipal().subtract(repaymentLogs.getCurrentRepaymentPrincipal());
        BigDecimal interestAmt = caseRepayment.getRepaymentInterest().subtract(repaymentLogs.getCurrentRepaymentInterest());
        BigDecimal litigationFines = caseRepayment.getRepaymentPenalty().subtract(repaymentLogs.getCurrentRepaymentPenalty());
        caseRepayment.setRepaymentPrincipal(principalAmt);
        caseRepayment.setRepaymentInterest(interestAmt);
        caseRepayment.setRepaymentPenalty(litigationFines);
        caseRepayment.setIsPay("0");
        int updateResNums = caseRepaymentMapper.update(caseRepayment);
        if (updateResNums <= 0) {
            throw new BusinessException(500, "审核异常！！", "");
        }
    }

    /**
     * 回滚调解已还金额
     *
     * @param repaymentLogs
     */
    private void mediationHandler(BsCaseRepaymentLogs repaymentLogs) {
        BsCaseMediation caseMediation = bsCaseMediationMapper.queryById(repaymentLogs.getRepaymentId());
        BigDecimal principalAmt = caseMediation.getRepaymentPrincipal().subtract(repaymentLogs.getCurrentRepaymentPrincipal());
        BigDecimal interestAmt = caseMediation.getRepaymentInterest().subtract(repaymentLogs.getCurrentRepaymentInterest());
        BigDecimal litigationFines = caseMediation.getRepaymentPenalty().subtract(repaymentLogs.getCurrentRepaymentPenalty());
        caseMediation.setRepaymentPrincipal(principalAmt);
        caseMediation.setRepaymentInterest(interestAmt);
        caseMediation.setRepaymentPenalty(litigationFines);
        caseMediation.setIsPay("0");
        int updateResNums = bsCaseMediationMapper.update(caseMediation);
        if (updateResNums <= 0) {
            throw new BusinessException(500, "审核异常！！", "");
        }
    }

    /**
     * 回滚和解已还金额
     *
     * @param repaymentLogs
     */
    private void reconciliationHandler(BsCaseRepaymentLogs repaymentLogs) {
        ReduceStagingTmp reduceStagingTmp = reduceStagingTmpMapper.queryById(repaymentLogs.getRepaymentId());
        //本金 利息 罚息 已还
        BigDecimal principalAmt = reduceStagingTmp.getRepaymentPrincipalAmount().subtract(repaymentLogs.getCurrentRepaymentPrincipal());
        BigDecimal interestAmt = reduceStagingTmp.getRepaymentInterestAmount().subtract(repaymentLogs.getCurrentRepaymentInterest());
        BigDecimal litigationFines = reduceStagingTmp.getRepaymentLitigationFines().subtract(repaymentLogs.getCurrentRepaymentPenalty());
        reduceStagingTmp.setRepaymentPrincipalAmount(principalAmt);
        reduceStagingTmp.setRepaymentInterestAmount(interestAmt);
        reduceStagingTmp.setRepaymentLitigationFines(litigationFines);
        reduceStagingTmp.setIsPay("0");
        int updateResNums = reduceStagingTmpMapper.update(reduceStagingTmp);
        if (updateResNums <= 0) {
            throw new BusinessException(500, "审核异常！！", "");
        }
    }

    /**
     * 判断审核项是否还清款项
     *
     * @param bsCaseRepayment
     * @return true:还清  false:未还清
     */
    private boolean caculateDefaultIsPay(BsCaseRepayment bsCaseRepayment) {
        //已还金额  >= 应还金额
        BigDecimal repaidAmt = nullValueToZero(bsCaseRepayment.getRepaymentPrincipal()).add(nullValueToZero(bsCaseRepayment.getRepaymentInterest()))
                .add(nullValueToZero(bsCaseRepayment.getRepaymentPenalty())).add(nullValueToZero(bsCaseRepayment.getRepaymentLitigationAmount()))
                .add(nullValueToZero(bsCaseRepayment.getRepaymentPreservationAmount()));

        BigDecimal repaymentAmt = nullValueToZero(bsCaseRepayment.getPrincipalAmount()).add(nullValueToZero(bsCaseRepayment.getInterestAmount()))
                .add(nullValueToZero(bsCaseRepayment.getLitigationFines())).add(nullValueToZero(bsCaseRepayment.getLitigationAmount()))
                .add(nullValueToZero(bsCaseRepayment.getPreservationAmount()));

        if (repaidAmt.compareTo(repaidAmt) > -1) {
            return true;
        }
        return false;
    }

    /**
     * 判断和解审核项是否还清款项
     *
     * @param reduceStagingTmp
     * @return true:还清  false:未还清
     */
    private boolean caculateReconciliationIsPay(ReduceStagingTmp reduceStagingTmp) {
        //已还金额  >= 应还金额
        BigDecimal repaidAmt = nullValueToZero(reduceStagingTmp.getRepaymentPrincipalAmount()).add(nullValueToZero(reduceStagingTmp.getRepaymentInterestAmount()))
                .add(nullValueToZero(reduceStagingTmp.getRepaymentLitigationFines()));

        BigDecimal repaymentAmt = nullValueToZero(reduceStagingTmp.getLawsuitPrincipalAmount()).add(nullValueToZero(reduceStagingTmp.getLawsuitInterestAmount()))
                .add(nullValueToZero(reduceStagingTmp.getLitigationFines()));

        if (repaidAmt.compareTo(repaidAmt) > -1) {
            return true;
        }
        return false;
    }


    /**
     * 判断调解审核项是否还清款项
     *
     * @param caseMediation
     * @return true:还清  false:未还清
     */
    private boolean caculateMeditionIsPay(BsCaseMediation caseMediation) {
        //已还金额  >= 应还金额
        BigDecimal repaidAmt = nullValueToZero(caseMediation.getRepaymentPrincipal()).add(nullValueToZero(caseMediation.getRepaymentInterest()))
                .add(nullValueToZero(caseMediation.getRepaymentPenalty()));

        BigDecimal repaymentAmt = nullValueToZero(caseMediation.getPrepaymentPrincipal()).add(nullValueToZero(caseMediation.getPrepaymentInterest()))
                .add(nullValueToZero(caseMediation.getPrepaymentPenalty()));

        if (repaidAmt.compareTo(repaidAmt) > -1) {
            return true;
        }
        return false;
    }


    /**
     * 空值处理为0值
     */
    private BigDecimal nullValueToZero(BigDecimal bigDecimal) {
        return bigDecimal == null ? BigDecimal.ZERO : bigDecimal;
    }
}
